package com.fdb.efp.nls.service.impl.yed;

import com.fdb.basic.framework.core.base.FrameworkService;
import com.fdb.basic.framework.core.util.FileUtil;
import com.fdb.basic.framework.core.util.StringUtil;
import com.fdb.basic.framework.core.util.TimeUtil;
import com.fdb.basic.framework.core.util.UUIDUtil;
import com.fdb.efp.nls.service.vo.YedSignResultVO;
import com.fdb.efp.nls.service.facade.yed.YedSettleCertService;
import com.fdb.efp.esb.common.constant.ElectronicSignatureConstant;
import com.fdb.efp.esb.common.constant.ElectronicSignatureEnums;
import com.fdb.efp.esb.service.bo.req.dzqz.ReqElectronicSignature3203Bean;
import com.fdb.efp.esb.service.bo.req.dzqz.ReqElectronicSignatureDL01Bean;
import com.fdb.efp.esb.service.bo.req.dzqz.info.ElectronicSignature3203BaseInfo;
import com.fdb.efp.esb.service.bo.req.dzqz.info.ElectronicSignature3203SignInfo;
import com.fdb.efp.esb.service.bo.req.dzqz.info.ElectronicSignature3203SignKeyWord;
import com.fdb.efp.esb.service.bo.req.dzqz.info.ElectronicSignature3203SignPosnInfArry;
import com.fdb.efp.esb.service.bo.resp.dzqz.RspElectronicSignature3203Bean;
import com.fdb.efp.esb.service.bo.resp.dzqz.RspElectronicSignatureDL01Bean;
import com.fdb.efp.esb.service.facade.dzqz.ElectronicSignatureService;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 结清证明服务
 *
 * @author liangcongming :2020/8/6 16:45
 * @version 0.1
 * @date 2020/8/6 16:45
 * @since 2020/8/6 16:45
 */
@Service("yedSettleCertService")
public class YedSettleCertServiceImpl implements YedSettleCertService, FrameworkService {

    private static Logger logger = LoggerFactory.getLogger(YedSettleCertServiceImpl.class);

    // 结清证明文件模板
    private static final String TEMP_FILE_NAME = "settle_cert_temp.pdf";

    //授权地址
    @Value("${gzcb.authaddr}")
    private String authaddr;

    //优e贷结清证明文件中文名
    @Value("${yed.settle.temp.name}") //结清证明
    private String contCnName;

    //优e贷结清证明文件模板存放路径
    @Value("${yed.settle.temp.path}") // /home/ocmuser/share/infile/yed/settle/
    private String contSavePath;

    //优e贷结清证明签章关键字
    @Value("${yed.settle.signKwd}") // 广州银行股份有限公司
    private String signKwd;

    @Autowired
    @Qualifier("electronicSignatureService")
    private ElectronicSignatureService electronicSignatureService;// 电子签章原子服务


    @Override
    public YedSignResultVO signature(String nlsApplySeq, String axqUserId, Map contentMap) throws Exception {
        logger.info("======>【优e贷结清证明签章服务】 调用cfca结清证明模板签章接口【3203】,结清证明签章开始：结清证明模板文件名为：" + TEMP_FILE_NAME + "  申请流水号为" + nlsApplySeq);
        try {
            ReqElectronicSignature3203Bean req3203Bean = getReqElectronicSignature3203Bean(nlsApplySeq, axqUserId, contentMap);

            RspElectronicSignature3203Bean resp3203Bean = electronicSignatureService.electronicSignatureSignUpContract(req3203Bean);

            if (Objects.isNull(resp3203Bean)) {
                return new YedSignResultVO(false, "【优e贷结清证明签章服务】调用cfca结清证明模板签章接口【3203】，返回的结清证明签署信息为空! 申请流水号：" + nlsApplySeq);
            }
            if (Objects.isNull(resp3203Bean.getContract())) {
                logger.error("【优e贷结清证明签章服务】调用cfca结清证明模板签章接口【3203】，返回的签署人信息为空! 申请流水号：" + nlsApplySeq);
                return new YedSignResultVO(false, "【优e贷结清证明签章服务】调用cfca结清证明模板签章接口【3203】，返回的结清证明签署人信息为空! 申请流水号：" + nlsApplySeq);
            }
            //获取结清证明合同号
            final String contrNo = resp3203Bean.getContract().getContrNo();
            if (StringUtils.isEmpty(contrNo)) {
                return new YedSignResultVO(false, "【优e贷结清证明签章服务】调用cfca结清证明模板签章接口【3203】，返回的结清证明合同号为空! 申请流水号：" + nlsApplySeq);
            }
            if (!"06".equals(resp3203Bean.getContract().getContrSt())) {
                return new YedSignResultVO(false, "【优e贷结清证明签章服务】调用cfca结清证明模板签章接口【3203】，返回的状态不为已完成! 申请流水号：" + nlsApplySeq);
            }
            String signTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            if (StringUtils.isNotEmpty(resp3203Bean.getContract().getCrtContrTm())) {
                signTime = LocalDateTime.parse(resp3203Bean.getContract().getCrtContrTm(), DateTimeFormatter.ofPattern("yyyyMMddHHmmss")).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            }
            return new YedSignResultVO(true, "结清证明签署成功", resp3203Bean.getContract().getContrNo(), signTime);
        } catch (Exception e) {
            logger.error("【优e贷结清证明签章服务】申请流水号：" + nlsApplySeq + " 执行结清证明签章出现异常，异常信息为：", e);
            return new YedSignResultVO(false, "【优e贷结清证明签章服务】申请流水号：" + nlsApplySeq + " 执行结清证明签章出现异常，异常信息为：" + e.getMessage());
        }
    }

    /**
     * 下载签章文件
     *
     * @param lmtApplySeq 申请流水号
     * @param cfcaContNO  安心签结清证明合同号
     * @param fileName    下载后的文件名
     * @return
     * @throws Exception
     */
    @Override
    public YedSignResultVO downSignFile(String lmtApplySeq, String cfcaContNO, String fileName) {
        logger.info("======> 调用cfca结清证明下载接口开始<====== 申请流水号：" + lmtApplySeq + "安心签结清证明编号：" + cfcaContNO);
        ReqElectronicSignatureDL01Bean reqDL01Bean = new ReqElectronicSignatureDL01Bean();
        //安心签结清证明号
        reqDL01Bean.setContrNo(cfcaContNO);
        try {
            RspElectronicSignatureDL01Bean respDL01Bean = electronicSignatureService.electronicSignatureDownloadContract(reqDL01Bean);
            logger.info("开始检验返回的文件流");
            if (StringUtil.isNullorBank(respDL01Bean.getContrFlStrm())) {
                logger.error("调用cfca结清证明下载接口，返回的结清证明文件流为空! 申请流水号：" + lmtApplySeq);
                return new YedSignResultVO(false, "调用cfca结清证明下载接口，返回的结清证明文件流为空! 申请流水号：" + lmtApplySeq);
            }
            String path = new StringBuffer(contSavePath).append(lmtApplySeq).append("/").toString();
            File file = new File(path);
            if (!file.exists()) {
                file.mkdir();
            }
            FileUtil.writeBytesToFile(Base64.getDecoder().decode(respDL01Bean.getContrFlStrm()), path, fileName);
            logger.info("下载结清证明到本地指定目录下:" + path + fileName);
            return new YedSignResultVO((ElectronicSignatureEnums.RetCodeEnum.SUCCESS.VALUE.equals(respDL01Bean.getRetStCd())) ? true : false, (ElectronicSignatureEnums.RetCodeEnum.SUCCESS.VALUE.equals(respDL01Bean.getRetStCd())) ? "下载文件成功" : respDL01Bean.getRtnMsg(), cfcaContNO, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), path + fileName);
        } catch (IOException ie) {
            logger.error("Base64转换文档失败", ie.getMessage());
            return new YedSignResultVO(false, ie.getMessage());
        } catch (Exception e) {
            logger.error("执行结清证明签章出现异常，异常信息为：", e.getMessage());
            return new YedSignResultVO(false, e.getMessage());
        }
    }

    private final ReqElectronicSignature3203Bean getReqElectronicSignature3203Bean(String nlsApplySeq, String axqUserId, Map contentMap) throws Exception {
        logger.info("======>【优e贷结清证明签章服务】,证明签章开始  申请流水号：" + nlsApplySeq);
        ReqElectronicSignature3203Bean req3203Bean = new ReqElectronicSignature3203Bean();
        // 组装结清证明模板签章接口请求包信息
        ElectronicSignature3203BaseInfo req3203BeanBase = new ElectronicSignature3203BaseInfo();

        // 是否签署，0：抄送；1：签署；2：暂不签署；默认为0 抄送代表不签客户章
        req3203BeanBase.setSignFlg(ElectronicSignatureConstant.IS_SIGN_1);
        // 印章ID = 客户开户号（安心签开户号） 印章ID
        // req3203BeanBase.setSealId(axqCusId);
        // 结清证明类型
        req3203BeanBase.setContrTp(ElectronicSignatureConstant.CONTRACT_TYPE_CODE_QT);
        // 结清证明名称
        req3203BeanBase.setContrNm(contCnName);

        // 关键字签章信息组装 ******************start*******************************
        ElectronicSignature3203SignKeyWord signKeyword = new ElectronicSignature3203SignKeyWord();
        //关键字 = 银行签章
        signKeyword.setSignKwd(signKwd);
        //X轴偏移坐标
        signKeyword.setXOfstCoordPosn("80");
        //Y轴偏移坐标
        signKeyword.setYOfstCoordPosn("-20");
        //签章图片宽度
        signKeyword.setSignImgWdth("150");
        //签章图片高度
        signKeyword.setSignImgHght("150");
        // 关键字签章信息组装 ******************end*******************************
        req3203BeanBase.setSignKeyword(signKeyword);

        //签名域签章信息组装 ******************start*******************************
        List<ElectronicSignature3203SignPosnInfArry> signPosnInfArry = new ArrayList<ElectronicSignature3203SignPosnInfArry>();
        ElectronicSignature3203SignPosnInfArry signLocation1 = new ElectronicSignature3203SignPosnInfArry();
        //签名域页数
        signLocation1.setSignOnPgCnt("1");
        //签名域的左下角X轴坐标值
        signLocation1.setSignPosnLBX("85");
        //签名域的左下角Y轴坐标值
        signLocation1.setSignPosnLBY("550");
        //签名域的右上角X轴坐标值
        signLocation1.setSignPosnRUX("140");
        //签名域的右上角Y轴坐标值
        signLocation1.setSignPosnRUY("575");
        signPosnInfArry.add(signLocation1);
        //签名域签章信息组装 ******************end*******************************
        req3203BeanBase.setSignPosnInfArry(signPosnInfArry);

        // 签署信息组装 ******************start*******************************
        List<ElectronicSignature3203SignInfo> signInfos = new ArrayList<ElectronicSignature3203SignInfo>();
        ElectronicSignature3203SignInfo signInfo1 = new ElectronicSignature3203SignInfo();
        //用户ID = 安心签开户号
        signInfo1.setUsrID(axqUserId);
        //授权时间
        signInfo1.setAuthTm(TimeUtil.getTimeStampByPattern("yyyyMMddHHmmss"));
        //授权地址
        signInfo1.setAuthAddr(authaddr);
        //项目编号
        signInfo1.setPrjNo("11110004");

        // TODO IF DELETE
//        //按关键字创建签名  @modify @date 2019/06/10
//        ElectronicSignature3203SignKeyWord2 signKeyWord2 = new ElectronicSignature3203SignKeyWord2();
//        //关键字 = 客户签章
//        signKeyWord2.setSignKwd(tempFileName.equals("sqs.pdf") ? "授权书签署日期" : "身份证号码");
//        signKeyWord2.setXOfstCoordPosn("50");
//        signKeyWord2.setYOfstCoordPosn(tempFileName.equals("sqs.pdf") ?"50":"30");
//        signKeyWord2.setSignImgHght("150");
//        signKeyWord2.setSignImgWdth("150");
//        signInfo1.setSignKeyword2(signKeyWord2);
//        //是否代签 1 代签
//        signInfo1.setAgncSignFlg(ElectronicSignatureConstant.IS_SIGN_1);
//        signInfo1.setCopyFlg(ElectronicSignatureEnums.YesNoEnum.NO.VALUE);
        signInfos.add(signInfo1);
        // 签署信息组装 ******************end*******************************
        req3203BeanBase.setSignBscInfArry(signInfos);
        // 获取结清证明流
        req3203Bean.setContrFlStrm(fillPdfContent(contentMap));
        req3203Bean.setUploadContract(req3203BeanBase);
        return req3203Bean;
    }


    public String fillPdfContent(Map<String, String> contractMap) throws Exception {
        String pdfFilePath = contSavePath + TEMP_FILE_NAME;
        if (!new File(pdfFilePath).exists()) {
            throw new Exception("根据pdf模板文件名获取到的模板文件不存在");
        }
        if (contractMap == null || contractMap.size() < 1) {
            throw new Exception("填充内容不能都为空");
        }
        logger.info("填充模板内容开始：");
        PdfReader pdfReader = null;
        FileOutputStream out = null;
        PdfStamper pdfStamper = null;
        File tmpFile = null;
        try {
            //获取结清证明模板文件
            pdfReader = new PdfReader(pdfFilePath);
            String tmpFileName = FilenameUtils.getFullPath(pdfFilePath) + UUIDUtil.getUUID() + ".pdf";
            //获取生成的结清证明放置的文件
            out = new FileOutputStream(tmpFileName);
            //获取表单操作工具
            pdfStamper = new PdfStamper(pdfReader, out);

            //新建支持中文的字体
            BaseFont baseFont = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);

            //获取表单中的变量
            AcroFields fields = pdfStamper.getAcroFields();

            //设置变量的内容生成后不可更改
            pdfStamper.setFormFlattening(true);

            //设置变量中的字体,并设置变量中的值
            contractMap.forEach((k, v) -> {
                fields.setFieldProperty(k, "textFont", baseFont, null);
                try {
                    fields.setField(k, v);
                } catch (Exception e) {
                    logger.error("填充内容报错", e);
                }
            });
            pdfStamper.flush();
            if (pdfStamper != null) {
                pdfStamper.close();
            }
            if (out != null) {
                out.close();
            }
            if (pdfReader != null) {
                pdfReader.close();
            }

            tmpFile = new File(tmpFileName);
            if (!tmpFile.exists()) {
                throw new RuntimeException("获取临时文件出错");
            }

            String rtBase64Str = fileToBase64Str(tmpFileName);
            if (StringUtils.isEmpty(rtBase64Str)) {
                throw new RuntimeException("填充模板文件出错，生成的文件为空");
            }
            //返回本地生成的结清证明文件的二进制流
            return rtBase64Str;
        } catch (Exception e) {
            throw new Exception("填充模板内容发生异常：", e);
        } finally { //关闭占用的资源文件
            if (pdfStamper != null) {
                pdfStamper.close();
            }
            if (out != null) {
                out.close();
            }
            if (pdfReader != null) {
                pdfReader.close();
            }
            if (tmpFile != null) {
                tmpFile.delete();
            }
        }
    }

    private String fileToBase64Str(String filePath) {
        File file = new File(filePath);
        if (file.isFile() && file.exists()) {
            try {
                byte[] bytes = Files.readAllBytes(Paths.get(file.getAbsolutePath()));
                return Base64.getEncoder().encodeToString(bytes);
            } catch (IOException e) {
                logger.error("文档转换成base64失败", e);
            }
        }
        return null;
    }

    /**
     * 删除从影像系统下载的临时文件
     *
     * @param filePath
     */
    private void deleteTempFile(String filePath) {
        File file = new File(filePath);
        if (file.exists()) {
            file.delete();
        }
    }

}
